﻿/*
 * Created by SharpDevelop.
 * User: phtrung
 * Date: 6/16/2009
 * Time: 1:58 PM
 * 
 * To change this template use Tools | Options | Coding | Edit Standard Headers.
 */

using System;
using System.Collections.Specialized;
using System.Collections.Generic;
using System.Drawing;
using System.Windows.Forms;
using System.IO;
using System.Threading;
using popLib;
using System.Text.RegularExpressions;
using System.Data;


namespace SplitMergeFile
{
	/// <summary>
	/// Description of MainForm.
	/// </summary>
	public partial class MainForm : Form
	{
		DataTable filetb = DataLib.initDataTable( "File [ name, path, destination, part, status ]" );
		
		public MainForm(string[] args)
		{
			//
			// The InitializeComponent() call is required for Windows Forms designer support.
			//
			InitializeComponent();
			dgv_list.DataSource = filetb;			
			//FormLib.setTransparentForm( this, 255, FormLib.FormBackground.VistaBlueContainer, new TransparentFormOption() );
			
			FormLib.dragAndDrop( this, DoDragDrop );
			FormLib.dragAndDrop( dgv_list, DoDragDrop );
			
			addFileToList( args );
		}
		
		#region Drag & Drop Actions
		
		
		void DoDragDrop( Control control, string[] files ){
			addFileToList(files);
		}
		
		string[] extensionStr = ".part1,.part01,.part001,.001,.01,.1,.a,.__a".Split(',');
		void addFileToList( string[] files ){
			foreach( string file in files ){				
				if( File.Exists(file) && 
				   filetb.Select( " path = '"+file+"' " ).Length == 0 && 
				   StringLib.indexOfAny( Path.GetExtension(file.ToLower()) , extensionStr ) > -1 )
				{
					filetb.Rows.Add( new string[] {
					                	Path.GetFileName(file),
					                	file,
					                	getDefaultOutputFile(file),
					                	getFileListPattern( file ).Count.ToString(),
					                	"Ready"
					                } );
				}
			}
		}
		
		#endregion
			
		#region Merge Functions
                
        long getTotalFileDataLength(string onefile) {
            long total = 0;
            List<string> files = getFileListPattern(onefile);
            foreach (string file in files)
            {
                total += (new FileInfo(file)).Length;
            }
            return total;
        }

        List<string> getFileListPattern(string file)
        {
            string filename = Path.GetFileName(file);
            string filePath = Path.GetDirectoryName(file);
            string extension = filename.Split('.')[filename.Split('.').Length - 1];
            string fileNoExt = Path.GetFileNameWithoutExtension(file);
            
            return getFileListPattern(filePath, fileNoExt, extension);
        }

        string getDefaultOutputFile(string file){
        	string output = Path.Combine(Path.GetDirectoryName(file), Path.GetFileNameWithoutExtension(file));
        	if( File.Exists( output ) ) output += ".out";
        	return output;
        }
        
		void preMerge(string file, string output){
            List<string> files = getFileListPattern(file);                        
			doMerge( output, files );
		}
		
		List<string> getFileListPattern(string path, string filename, string extension){
			
			bool fileFound = true;
			List<string> files = new List<string>();
			string prefix   = Regex.Match( extension, "[^0-9]+" ).Value;
			string counter  = Regex.Match( extension, "[0-9]+" ).Value;
			
			if( StringLib.isValid( counter ) ){ //if counter is valid
				
				int index = Convert.ToInt16( counter );				
				while( fileFound ){
					string nextFile = path + "\\" + filename +"."+ prefix + StringLib.spaceleft( index+"", counter.Length, "0" ) + index;
					nextFile = nextFile.Replace(@"\\",@"\");
					if( File.Exists( nextFile ) ){
						files.Add( nextFile );
						index++;
					}else fileFound = false;
				}
			}else { //counter not valid				
				string indexChar = extension[extension.Length-1].ToString();
				int index 		 = Convert.ToInt16( extension[extension.Length-1] ) ;
				while( fileFound ){					
					string nextFile = path + "\\" + filename +"."+ extension.Substring(0, extension.Length-1) + Convert.ToChar(index) ;
					nextFile = nextFile.Replace(@"\\",@"\");
					if( File.Exists( nextFile ) ){
						files.Add( nextFile );
						index++;
					}else fileFound = false;
				}
			}
			return files;
		}
		FileStream outFile;
		FileStream inFile;
		int bufferSize = 32000;
		void doMerge( string output, List<string> files){			
			
			outFile = new FileStream(output, FileMode.OpenOrCreate, FileAccess.Write);			
			long getted = 0;
			byte[] buffer;
			int currentPercent = 0;
            double onePartPercent = 100 / files.Count;
            double beginPercent = 0;
			for (int i=0;i<files.Count; i++)
			{							
				inFile = new FileStream( files[i] ,FileMode.OpenOrCreate, FileAccess.Read);
				getted = 0;
				while( getted < inFile.Length ){
					
					if( bufferSize > inFile.Length - getted )
						buffer = new byte[inFile.Length - getted];
					else buffer = new byte[bufferSize];
					
					inFile.Read(   buffer, 0, buffer.Length);
					outFile.Write( buffer, 0, buffer.Length );
                    outFile.Flush();
					
					getted += buffer.Length;
                    totalDataLengthMerged += buffer.Length;
					
					currentPercent = (int)((getted * 100) / inFile.Length);
                    viewProgressBar( files[i], currentPercent, progressBar1);
					
                    
                    beginPercent   = i * onePartPercent;
					currentPercent = (int)( beginPercent + ((currentPercent * onePartPercent) / 100)) ;
                    viewProgressBar( output, currentPercent, progressBar2);

                    currentPercent = (int)((totalDataLengthMerged * 100) / totalDataLength);
                    viewProgressBar( "Total together", currentPercent, progressBar3);


					
				}				
				inFile.Close();
			}
			outFile.Close();
		}
		#endregion
		
		Thread main;
		void Btn_mergeClick(object sender, EventArgs e)
		{
			main = new Thread( new ThreadStart( ProcessMerge ) );
			main.IsBackground = true;
			main.Start();
			
			btn_open.Enabled = btn_merge.Enabled = false;
			btn_stop.Enabled = true;
		}
		
		

        long totalDataLength = 0;
        long totalDataLengthMerged = 0;
		void ProcessMerge(){
            totalDataLengthMerged = totalDataLength = 0;
			foreach( DataRow row in filetb.Rows )
            	totalDataLength += getTotalFileDataLength(row["path"].ToString());
			
			foreach( DataRow row in filetb.Rows ){
				row["status"] = "Merging";
				preMerge( row["path"].ToString(), row["destination"].ToString() );
				row["status"] = "Done";
			}

            FormLib.alert("Merge files completed.");
			ThreadStart ts = delegate{ Btn_stopClick(null, new EventArgs()); };
			this.Invoke( ts );            
		}
		
		
		void Btn_stopClick(object sender, EventArgs e)
		{
			main.Abort();
			if( outFile != null ) outFile.Close();
			if( inFile != null ) outFile.Close();
			btn_open.Enabled = btn_merge.Enabled = true;
			btn_stop.Enabled = false;
		}
		
		void Btn_openClick(object sender, EventArgs e)
		{
			ReturnSet rs = FormLib.openFile( "All files(*.*)|*.*", null, true );
			if( !rs.Success ) return;
			addFileToList((string[])rs.Result);
		}
		
		void viewProgressBar( string text, int percent, ProgressBar pgbar ){
			ThreadStart ts = delegate{
				pgbar.Value = percent > 100 ? 100: percent;
                string content = (StringLib.isValid(text) ? text + " - " + percent : percent.ToString()) + "%";
                using (Graphics gr = pgbar.CreateGraphics())
                {
                    gr.DrawString(content,
                        SystemFonts.DefaultFont,
                        Brushes.Black,
                        new PointF(
                            pgbar.Width / 2 - (gr.MeasureString(content, SystemFonts.DefaultFont).Width / 2.0F),
                            pgbar.Height / 2 - (gr.MeasureString(content, SystemFonts.DefaultFont).Height / 2.0F)
                        )
                   );
                }
			};
			this.Invoke( ts );
			
		}
		
		void Dgv_listCellClick(object sender, DataGridViewCellEventArgs e)
		{
			if( e.RowIndex >= 0 && e.ColumnIndex == 2 ){
				string file = FormLib.saveFile("All files(*.*)|*.*", filetb.Rows[e.RowIndex][2].ToString() );
				if( StringLib.isValid(file) ){
					filetb.Rows[e.RowIndex][2] = file;
				}
			}
		}
	}
}
